package middleware

import (
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"higame/config"
	"higame/modules/role"
	_ "higame/modules/role"
	"higame/modules/store"
	"higame/modules/utils"
	"net/http"
	"strconv"
	"strings"
)

func Auth() gin.HandlerFunc {
	return func(ctx *gin.Context) {
		//所有get请求都放行
		if ctx.Request.Method == "GET" {
			ctx.Next()
			return
		}

		reqUri := ctx.Request.URL.Path
		// 路由白名单无需验证授权
		if utils.ContainsValue(role.WhiteListRoutes, reqUri) {
			ctx.Next()
			return
		}

		// 开始验证授权
		auth := ctx.Request.Header.Get("Authorization")
		if len(auth) == 0 {
			ctx.JSON(401, gin.H{
				"code": 401, // 过期状态码
				"msg":  "用户验证失败，请重新登录！",
				"data": nil,
			})
			ctx.Abort()
			return
		}
		// 校验token
		auth = strings.Fields(auth)[1]
		claims, err := parseToken(auth)
		if err != nil {
			ctx.JSON(http.StatusUnauthorized, gin.H{
				"code": http.StatusUnauthorized, // 过期状态码
				"msg":  "用户验证失败，请重新登录！",
				"data": nil,
			})
			ctx.Abort()
			return
		}

		// 校验通过
		roleType, err := strconv.ParseInt(claims.Issuer, 10, 64)
		if err != nil {
			ctx.JSON(http.StatusInternalServerError, gin.H{
				"code": http.StatusInternalServerError,
				"msg":  "服务器内部错误",
				"data": nil,
			})
			ctx.Abort()
			return
		}
		// 获取当前登录用户可能访问的路由表
		routeMap := role.GetAccessibleRoutesByRole(role.Type(roleType))
		// 效验用户是否有权限访问当前路由
		if !utils.ContainsValue(routeMap, reqUri) {
			ctx.JSON(http.StatusUnauthorized, gin.H{
				"code": http.StatusUnauthorized,
				"msg":  "您所在的用户组权限太低,无法完成此操作！",
				"data": nil,
			})
			ctx.Abort()
			return
		}
		store.SetClaims(ctx, claims)
		ctx.Next()
	}
}

func parseToken(token string) (*jwt.StandardClaims, error) {
	jwtToken, err := jwt.ParseWithClaims(token, &jwt.StandardClaims{}, func(token *jwt.Token) (i interface{}, e error) {
		return []byte(config.Secret), nil
	})
	if err == nil && jwtToken != nil {
		if claim, ok := jwtToken.Claims.(*jwt.StandardClaims); ok && jwtToken.Valid {
			return claim, nil
		}
	}
	return nil, err
}
